package com.corpgovernment.common.entity;

import com.corpgovernment.common.base.CommonException;
import lombok.extern.slf4j.Slf4j;

/**
 * @author ：xks
 * @date ：Created in 2022/5/13 14:40
 * @description：
 * @modified By：
 * @version: $
 */
@Slf4j
public abstract class BaseServiceHandler<T, R> {

    protected abstract String getActionName();

    /**
     * 1.1处理校验失败的请求，并返回响应报文
     *
     * @param request
     * @param exception
     * @return
     */
    protected abstract R handleVerifyFailure(T request, CommonException exception);


    /**
     * 阶段1.2: 处理服务器异常，并返回响应报文。
     *
     * @param th
     * @return
     */
    protected abstract R handleServerException(T request, Throwable th);

    /**
     * 阶段1：校验请求 校验失败通过抛出CommonException方式返回失败。
     */
    protected abstract void verify(T request) throws CommonException;

    /**
     * 阶段2：初始化上下文，建议Override。
     * <p>
     * 由具体实现类去构造上下文，具体内容可以是下面的。 1. 构建内部实体类的 request，并放到context中。 2. 构建当前transaction的config或开关 3.
     * 构建其他业务流程中的公共属性，调试、子请求、语言、币种汇率等。
     */
    protected BaseContext createContext() {
        return new BaseContext();
    }

    /**
     * 阶段3：初始化： 1. 初始化上下文属性 2. 初始化缓存 3. 初始化配置
     */
    protected abstract void initialize(T request);

    /**
     * 阶段4：处理请求 返回结果，不得通过抛出异常方式中断业务流程。
     */
    protected abstract R doProcess(T request);

    /**
     * 阶段5：装饰响应结果 用于后期处理： 可能操作： 1. 多语言化 2. 多币种化 3. 数据加密 4. 日志处理
     */
    protected abstract R decorateResponse(R response);

    private String getLogTitle() {
        return this.getActionName();
    }

    public R process(T request) {
        R response = null;
        try {
            // 1. 校验
            verify(request);
            // 2. 创建上下文
            BaseContext context = createContext();
            // 3. 初始化请求
            this.initializeCommonContext(request);
            this.initialize(request);
            // 4. 处理请求
            response = doProcess(request);
            // 5. 装饰响应报文
            response = decorateResponse(response);
        } catch (CommonException verifyFail) {
            // 1.1 处理校验失败
            response = handleVerifyFailure(request, verifyFail);
        } catch (Exception ex) {
            // 1.2 处理未知异常
            response = handleServerException(request, ex);
            // 记录异常日志
            log.error(this.getLogTitle(), ex);
        } finally {
            BaseContext.remove();
        }
        return response;
    }

    private void initializeCommonContext(T request) {
        BaseContext context = BaseContext.get();
        context.put(BaseContext.REQUEST, request);
        context.put(BaseContext.ACTION, this.getActionName());
    }
}
